package com.hliushi.spark.sql

import org.apache.commons.lang3.StringUtils
import org.apache.spark.sql.{DataFrame, SparkSession}

/**
 * descriptions:
 *
 * author: Hliushi
 * date: 2021/5/20 14:54
 */
object UDF {

  import org.apache.spark.sql.functions._

  // 1.创建SparkSession
  val spark: SparkSession = SparkSession.builder()
    .appName("window")
    .master("local[6]")
    .getOrCreate()

  import spark.implicits._

  /**
   *
   * @param args
   */
  def main(args: Array[String]): Unit = {


    val source: DataFrame = Seq(
      ("Thin", "Cell phone", 6000),
      ("Norma1", "tablet", 1500),
      ("Mini", "tablet", 5500),
      ("Uitra thin", "cell phone", 5000),
      ("Very thin", "cell phone", 6000),
      ("Big", "Tablet", 2500),
      ("Bendab1e", "Cell phone", 3000),
      ("Fo1dable", "Cell phone", 3000),
      ("Pro", "Tablet", 4500),
      ("Pro2", "Tablet", 6500)
    ).toDF("product", "category", "revenue")



    // 需求1: 聚合每个类别的总价
    // 1.分组
    // 2.对每一组的数据进行聚合
    source.groupBy($"category")
      //.sum("revenue")
      //.withColumnRenamed("sum(revenue)", "revenue_sum")
      .agg(sum($"revenue") as "revenue_sum")
      .show()
    //  +----------+-----------+
    //  |  category|revenue_sum|
    //  +----------+-----------+
    //  |Cell phone|      23000|
    //  |    Tablet|      20500|
    //  +----------+-----------+

    // 需求2: 把名称变成小写
    source.select(lower($"product"))
      .show()
    //  +--------------+
    //  |lower(product)|
    //  +--------------+
    //  |          thin|
    //  |        norma1|
    //  |          mini|
    //  |    uitra thin|
    //  |     very thin|
    //  |           big|
    //  |      bendab1e|
    //  |      fo1dable|
    //  |           pro|
    //  |          pro2|
    //  +--------------+

    //  需求2.1: 将名称首字母变成大写
    /**
     * 这里都  lower02 _  是将 方法lower02 准换为函数
     * def udf[RT: TypeTag, A1: TypeTag](f: Function1[A1, RT]): UserDefinedFunction
     */
    spark.udf.register("toLower0", lower02 _)
    spark.udf.register("toUpper0", upper02 _)
    val toLower = udf(lower02 _)
    val toUpper = udf(upper02 _)

    source.select($"product",
      toLower($"product") as "toLower_pro",
      toUpper($"category") as "toUpper_cate")
      .show()

    source.selectExpr("toLower0(product) as toLower_pro, toUpper0(category) as toUpper_cate")
      .show()


    // 需求3: 把价格变成字符串形式
    // 6000  -> 6K
    //source.select($"revenue".as[String]).show()

    /**
     * toStrUDF是一个函数
     * #
     * UserDefinedFunction类中 apply方法
     * def apply(exprs: Column*): Column
     */
    val toStrUDF = udf(toStr _)
    source.select($"product", $"category", toStrUDF($"revenue"))
      .show()
    //  +----------+----------+------------+
    //  |   product|  category|UDF(revenue)|
    //  +----------+----------+------------+
    //  |      Thin|Cell phone|        6.0K|
    //  |    Norma1|    Tablet|        1.5K|
    //  |      Mini|    Tablet|        5.5K|
    //  |Uitra thin|Cell phone|        5.0K|
    //  | Very thin|Cell phone|        6.0K|
    //  |       Big|    Tablet|        2.5K|
    //  |  Bendab1e|Cell phone|        3.0K|
    //  |  Fo1dable|Cell phone|        3.0K|
    //  |       Pro|    Tablet|        4.5K|
    //  |      Pro2|    Tablet|        6.5K|
    //  +----------+----------+------------+

  }


  /**
   * 把价格变成字符串形式 例如 6000K --> 6.0K  2500 --> 2.5K
   *
   * @param revenue
   * @return
   */
  def toStr(revenue: Long): String = {
    val revenueDou = revenue.toDouble
    (revenueDou / 1000) + "K"
  }

  /**
   * 自定义UDF, 将单词的首字母小写
   * 时间: 2021年5月30日07:51:13 由于对Java中的正则表达式使用未完全理解,
   * .      或者正则表达式需要在Java使用各种转义字符, 这里只采用使用Scala中正则表达式
   *
   * @param str
   * @return
   */
  def lower02(str: String): String = {
    val regEx = """^[A-Z]+""".r
    // 第二个正则表达式判断, "antion" 首字母是小写才为true , 注意 " antion" 这样的结果为false, 因为字符串第一个元素为空
    if (StringUtils.isNotBlank(str) && regEx.findAllMatchIn(str).size == 1) {
      str.replace(str.charAt(0), str.charAt(0).toLower)
    } else {
      str
    }
  }

  /**
   * 自定义UDF, 将单词的首字母大写
   *
   * @param str
   * @return
   */
  def upper02(str: String): String = {
    val regEx = """^[a-z]+""".r
    // 第二个正则表达式判断, "antion" 首字母是小写才为true , 注意 " antion" 这样的结果为false, 因为字符串第一个元素为空
    if (StringUtils.isNotBlank(str) && regEx.findAllMatchIn(str).size == 1) {
      str.replace(str.charAt(0), str.charAt(0).toUpper)
    } else {
      str
    }
  }
}